#include "testApp.h"


//--------------------------------------------------------------
void testApp::setup(){

	//Load images
	string basedir = "Odder_DSC_0122";

	//load images
	drawing.loadImage("drawing.png", basedir, OF_IMAGE_COLOR_ALPHA);
	drawing.name = "Drawing";
	contour.loadImage("contour.png", basedir, OF_IMAGE_GRAYSCALE);
	contour.name = "Contour";
	drawing_gs = drawing;
	drawing_gs.setImageType(OF_IMAGE_GRAYSCALE);
	drawing_gs.name = "Drawing grayscale";
	photo.loadImage("photo.png", basedir, OF_IMAGE_COLOR);
	photo.name = "Photo";

	//set windows size
	ofSetWindowShape(drawing.width, drawing.height);

	//set initial filter target
	filterTarget = &photo;
	nextFilterOP = nullptr;
	previousFilterOP = nullptr;
	filterParam = 1;
	counter = 1;
	grow = false;

	//init random generator
	srand(time(nullptr));
}


//--------------------------------------------------------------
void testApp::update(){

	printState();

	//Filter current target
	if(nextFilterOP != nullptr){
		cout << "Filtering"<<endl;
		if(filterTarget == &drawing_gs){
			updateAlphaMasking = true;
			cout << "Filtering grayscale drawing" << endl;
		}

		if(previousFilterOP == nextFilterOP){
			if(filterTarget != &drawing_gs || !alphaDirty){
				filterTarget->restore();
			} 
		}

		(filterTarget->*nextFilterOP)(filterParam);
		filterTarget->commitFilterOps();

		previousFilterOP = nextFilterOP;
		previousFilterOpName = filterOpName;
		nextFilterOP = nullptr;
	}

	//Calculate greyscale alpha mask
	if(grow || shrink){
		cout << "Alphamask " << (grow ? "grow" : "shrink") << endl;
		UpdateAlphaMask();
		updateAlphaMasking = true;
		alphaDirty = true;
	} 

	//Apply alpha mask to image
	if(updateAlphaMasking){
		cout << "Apply alpha mask"  << endl;
		for(int i=0; i<drawing.pixelcount; i++){
			drawing[i*4+3] = drawing_gs[i];
		}
		drawing.commitPixelOps();
		updateAlphaMasking = false;
	}
}


void testApp::UpdateAlphaMask()
{
	UCHAR* pixels = drawing_gs.getPixels();
	const int wstep = drawing_gs.width;
	const int pixelceill = drawing_gs.pixelcount-1-wstep;
	int count = 0;
	int kval = 0;
	int pval = 0;
	const int max = 240;
	const int min = 10;
	int smin = 0;
	int smax = 255;

	for(int i=1+wstep; i< pixelceill; i++, pixels++){

		if((*pixels) > 50){

			smin = 255;
			smax = 0;

			minmaxsum(*(pixels-wstep-1), smin, smax, kval);
			minmaxsum(*(pixels-wstep), smin, smax, kval);
			minmaxsum(*(pixels-wstep+1), smin, smax, kval);
			minmaxsum(*(pixels-1), smin, smax, kval);
			minmaxsum(*(pixels+1), smin, smax, kval);
			minmaxsum(*(pixels+wstep-1), smin, smax, kval);
			minmaxsum(*(pixels+wstep), smin, smax, kval);
			minmaxsum(*(pixels+wstep+1), smin, smax, kval);
			kval /= 8;

			pval = *pixels;
			if(abs(smin-smax) > 50){
				if(grow){
					pval -= rand() % 63;
					*pixels = pval > 0 ? pval : 0;
				}					
				else{
					pval += rand() % 63;
					*pixels = pval < 255 ? pval : 255;
				}
				count++;
			}
		}
	}

	cout << count << " pixels modified" << endl;
	shrink = grow = false;
	drawing_gs.commitPixelOps();
}

void testApp::fillKernelOffsets( int widthStep, int& kernel, int kernelWidth, int kernelHeigth )
{

}


void testApp::draw(){

	ofSetColor(0xFFFFFF);

	ofEnableAlphaBlending();
	photo.draw();
	drawing.draw();

	if(preview){drawPreview(*filterTarget);}
	
}


////--------------------------------------------------------------
void testApp::keyPressed(int key){

	nextFilterOP = nullptr;

	//Select filter target
	if(key == '1'){
		filterTarget = &photo;
	}
	else if(key == '2'){
		filterTarget = &contour;
	}
	else if(key == '3'){
		filterTarget = &drawing_gs;
	}

	//Set filter iterations
	else if(key == OF_KEY_F1){
		if(filterParam > 1){
			filterParam--;
			std::cout << "Decrease filter parameter to "<<filterParam << endl;
		}
	}
	else if(key == OF_KEY_F2){
		filterParam++;
		std::cout << "Increase filter parameter to "<<filterParam << endl;
	}
	else if(key == OF_KEY_F3){
		preview = !preview;
	}

	//Select filter operation
	else if(key == 'o'){			//open
		nextFilterOP = &ofxImage::open;
		filterOpName = "Open";
	}
	else if(key == 'c'){			//close
		nextFilterOP = &ofxImage::close;
		filterOpName = "Close";
	}
	else if(key == 't'){			//tophat
		nextFilterOP = &ofxImage::tophat;
		filterOpName = "Tophat";
	}
	else if(key == 'b'){			//blackhat
		nextFilterOP = &ofxImage::blackhat;
		filterOpName = "Blackhat";
	}	
	else if(key == 'm'){			//threshold
		//TODO crash
		filterTarget->threshold(filterParam);
	}
	else if(key == 'd'){			//dilate
		nextFilterOP = &ofxImage::dilate;
		filterOpName = "Dilate";
	}
	else if(key == 'e'){			//erode
		nextFilterOP = &ofxImage::erode;
		filterOpName = "Erode";
	}
	else if(key == 's'){			//blur
		nextFilterOP = &ofxImage::blur;
		filterOpName = "Blue";
	}
	else if(key == 'g'){			//gaussian blur
		nextFilterOP = &ofxImage::blurgaussian;
		filterOpName = "Gaussian blur";
	}
	//Restore image
	else if(key == 'r'){
		previousFilterOP = nextFilterOP = nullptr;
		filterTarget->restore();
		alphaDirty = false;
		updateAlphaMasking = true;
	}


	//Change filter size
	else if(key == '+' && previousFilterOP != nullptr){
		filterTarget->changeFilterSize(2,2);
		nextFilterOP = previousFilterOP;
	}
	else if(key == '-' && previousFilterOP != nullptr){
		filterTarget->changeFilterSize(-2,-2);
		nextFilterOP = previousFilterOP;
	}


	//ROI
	else if(key == OF_KEY_F5){
		filterTarget->setRoi(50,50, 100, 100);
	} 
	else if(key == OF_KEY_F6){
		filterTarget->setRoi(0,0, filterTarget->width, filterTarget->height);
	} 
	
	//Grow and shrink
	else if(key == 'p'){
		grow = true;
	}
	else if(key == 'l'){
		shrink = true;
	}


}

void testApp::printState()
{
	system("cls");

	if(filterTarget != nullptr){
		cout << "Filter target: " << filterTarget->name << endl;
		cout << "Filter properties: ";
		printFilterInfo(filterTarget->getFilterProperties());
	} else{
		cout << "Filter target: none" << endl;
	}

	if(previousFilterOP != nullptr){
		cout << "Last filter operation: " << previousFilterOpName << endl;
	} else{
		cout << "Last filter operation: none" << endl;
	}

	cout << "Filter parameter: " << filterParam << endl;
}

void testApp::printFilterInfo(filterProperties prop)
{
	cout << "Filter size "<< prop.width << " * " << prop.heigth << ". Anchor "<< prop.anchorX << ", "<<prop.anchorY << endl;
}

void testApp::drawPreview(ofxImage& content)
{
	ofDisableAlphaBlending();
	content.draw(20, drawing.height-169, 296, 149);
	ofSetColor(64,64,64,200);
	ofSetLineWidth(2);
	ofRect(19, drawing.height-170, 297, 151);
}

void testApp::minmaxsum( int v, int &smin, int &smax, int &kval )
{
	if(v < smin){ smin = v;}
	if(v > smax){ smax = v;}
	kval += v;
}
